use std::{net::TcpStream, io::Read, error::Error, thread, time::Duration};

pub struct UnblockReader {
    inner: TcpStream,
    buf: [u8; 1024],
    single_buf: [u8; 1],
}

impl UnblockReader {
    pub fn from(stream: &TcpStream) -> Result<Self, Box<dyn Error>> {
        let clone = stream.try_clone().unwrap();
        match clone.set_nonblocking(true) {
            Ok(_) => {
                Ok(Self { inner: clone, buf: [0_u8; 1024], single_buf: [0_u8; 1] })
            },
            Err(_) => Err("Can't set stream non blocking".into()),
        }
    }

    pub fn read(&mut self, bytes: &mut Vec<u8>) -> Result<usize, Box<dyn Error>> {
        match self.inner.read(&mut self.buf) {
            Ok(size) => {
                if size > 0 {
                    bytes.append(&mut self.buf[0..size].to_vec());
                }
                return Ok(size)
            },
            Err(e) => { 
                if e.kind() == std::io::ErrorKind::WouldBlock {
                    thread::sleep(Duration::from_millis(10));
                    return Ok(0)
                }
                Err("Read from target stream error".into()) 
            },
        }
    }

    pub fn next(&mut self) -> Result<Option<u8>, Box<dyn Error>> {
        match self.inner.read(&mut self.single_buf) {
            Ok(s) => {
                if s > 0 {
                    return Ok(Some(self.single_buf[0]))
                }
                return Ok(None)
            },
            Err(e) => { 
                if e.kind() == std::io::ErrorKind::WouldBlock {
                    thread::sleep(Duration::from_millis(10));
                    return Ok(None)
                }
                Err("Read from target stream error".into()) 
            },
        }
    }
}